/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "vertexdeclaration.h"
#include "color.h"

namespace Engine
{
	/**********************************************************************************************************/
	VertexElement::VertexElement(unsigned short source, size_t offset, VertexElementType theType, VertexElementSemantic semantic, unsigned short index)
		:m_source(source)
		,m_offset(offset)
		,m_type(theType)
		,m_semantic(semantic)
		,m_index(index)
	{
	}
	/**********************************************************************************************************/
	size_t VertexElement::GetSize(void) const
	{
		switch(m_type)
		{
		case VET_COLOR:
		case VET_COLOR_ABGR:
		case VET_COLOR_ARGB:
			return sizeof(RGBA);
		case VET_FLOAT1:
			return sizeof(float);
		case VET_FLOAT2:
			return sizeof(float)*2;
		case VET_FLOAT3:
			return sizeof(float)*3;
		case VET_FLOAT4:
			return sizeof(float)*4;
		case VET_SHORT1:
			return sizeof(short);
		case VET_SHORT2:
			return sizeof(short)*2;
		case VET_SHORT3:
			return sizeof(short)*3;
		case VET_SHORT4:
			return sizeof(short)*4;
		case VET_UBYTE4:
			return sizeof(unsigned char)*4;
		}
		return 0;
	}
	/**********************************************************************************************************/
	VertexDeclaration::VertexDeclaration()
	{
	}
	/**********************************************************************************************************/
	VertexDeclaration::~VertexDeclaration()
	{
	}
	/**********************************************************************************************************/
	const VertexElement* VertexDeclaration::GetElement(unsigned short index)const
	{
		if(index < m_elementList.size())
		{
	        VertexElementList::const_iterator i = m_elementList.begin() + index;
			return &(*i);
		}
		return 0;
	}
	/**********************************************************************************************************/
	const VertexElement& VertexDeclaration::AddElement(unsigned short source, size_t offset, VertexElementType theType, VertexElementSemantic semantic, unsigned short index)
	{
		// Refine colour type to a specific type
		if (theType == VET_COLOR)
		{
#ifdef _WIN32
			theType = VET_COLOR_ARGB;
#else
			theType = VET_COLOR_ABGR;
#endif
		}
		m_elementList.push_back(VertexElement(source, offset, theType, semantic, index));
		return m_elementList.back();
	}
	/**********************************************************************************************************/
	void VertexDeclaration::RemoveElement(unsigned short elem_index)
	{
		if(elem_index < m_elementList.size())
		{
			VertexElementList::iterator i = m_elementList.begin() + elem_index;
			m_elementList.erase(i);
		}
	}
	/**********************************************************************************************************/
	void VertexDeclaration::RemoveElement(const VertexElement* elem)
	{
			VertexElementList::iterator i = m_elementList.begin(), e = m_elementList.end();
			for(; i != e; ++i)
			{
				if(&(*i) == elem)
				{
					m_elementList.erase(i);
					break;
				}
			}
	}
	/**********************************************************************************************************/
	void VertexDeclaration::RemoveAllElements(void)
	{
		m_elementList.clear();
	}
	/**********************************************************************************************************/
    size_t VertexDeclaration::GetVertexSize(unsigned short source)const
	{
		VertexElementList::const_iterator i, iend;
		iend = m_elementList.end();
		size_t sz = 0;

		for (i = m_elementList.begin(); i != iend; ++i)
		{
			if (i->GetSource() == source)
			{
				sz += i->GetSize();
			}
		}
		return sz;
	}
	/**********************************************************************************************************/
	const VertexElement* VertexDeclaration::FindElementBySemantic(VertexElementSemantic sem, unsigned short index)const
	{
		VertexElementList::const_iterator ei, eiend;
		eiend = m_elementList.end();
		for (ei = m_elementList.begin(); ei != eiend; ++ei)
		{
			if (ei->GetSemantic() == sem && ei->GetIndex() == index)
			{
				return &(*ei);
			}
		}

		return NULL;
	}
	/**********************************************************************************************************/
	void VertexDeclaration::UpdateOffsets()
	{
		size_t offset = 0;
		VertexElementList::iterator ei, eiend;
		eiend = m_elementList.end();
		for (ei = m_elementList.begin(); ei != eiend; ++ei)
		{
			ei->m_offset = offset;
			offset += ei->GetSize();
		}
	}
	/**********************************************************************************************************/
}
